﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MediaScraper.Common;
using MediaScraper.DataAccess.Entities;
using OSDBnet;

namespace MediaScraper.Agents.OSDB
{
    public class OSDBAgent : IMediaAgent
    {
        private const string AgentName = "OS Test User Agent";
        
        public OSDBAgent()
        {

        }

        public VideoInfo GetInfoByFile(string filePath, List<CultureInfo> subtitleCultures)
        {
            using (var osdb = Osdb.Login("eng", AgentName))
            {
                if (File.Exists(filePath))
                {
                    var subtitles = new List<Subtitle>();
                    foreach (var subtitleCulture in subtitleCultures)
                    {
                        var res = osdb.SearchSubtitlesFromFile(GetLanguageCode(subtitleCulture), filePath);
                        subtitles.AddRange(res);
                    }
                    return subtitles.Count == 0 ? null : ProcessRequest(filePath, subtitles, subtitleCultures);
                }
            }
            return null;
        }

        public VideoInfo GetInfoByFileName(string fileName, List<CultureInfo> subtitleCultures)
        {
            using (var osdb = Osdb.Login("eng", AgentName))
            {
                var subtitles = new List<Subtitle>();
                foreach (var subtitleCulture in subtitleCultures)
                {
                    var res = osdb.SearchSubtitlesFromQuery(GetLanguageCode(subtitleCulture), fileName);
                    subtitles.AddRange(res);
                }
                return subtitles.Count == 0 ? null : ProcessRequest(fileName, subtitles,subtitleCultures);
            }
        }

        public string DownloadSubtitle(Uri url, string path, string fileName)
        {
            using (var osdb = Osdb.Login("eng", AgentName))
            {
                return osdb.DownloadSubtitleToPath(path,fileName,url);
            }
        }

        private VideoInfo ProcessRequest(string name, IList<Subtitle> subtitles, List<CultureInfo> cultures)
        {

            foreach (var subtitle in subtitles)
            {
                Debug.WriteLine(subtitle.SubtitleFileName);
            }

            var subs = new List<Subtitle>();
            VideoInfo result = null;
            var file = Path.GetFileNameWithoutExtension(name);
            foreach (var cultureInfo in cultures)
            {
                if (subtitles.Any(
                    x =>
                    x.SubtitleFileName.Contains(file) &&
                    x.LanguageId == GetLanguageCode(cultureInfo)))
                {
                    subs.Add(
                        subtitles.FirstOrDefault(
                            x =>
                            x.SubtitleFileName.Contains(file) &&
                            x.LanguageId == GetLanguageCode(cultureInfo)));
                }
                else if (subs.All(x => x.LanguageId != GetLanguageCode(cultureInfo)))
                {
                    subs.Add(subtitles.FirstOrDefault(x => x.LanguageId == GetLanguageCode(cultureInfo)));
                }
            }




            var sub = subs.FirstOrDefault();
            if (sub.MovieKind.ToLower().Contains("episode") || sub.MovieKind.ToLower().Contains("serie"))
            {
                result = new SeriesInfo
                    {
                        SeriesName = ExtractSeriesName(sub.MovieName),
                        Name = ExtractEpisodeName(sub.MovieName),
                        Episode = Convert.ToInt32(sub.SeriesEpisode),
                        Season = Convert.ToInt32(sub.SeriesSeason),
                        Year = sub.MovieYear
                    };
            }
            else
            {
                result = new VideoInfo
                {
                    Name = sub.MovieName,
                    Year = sub.MovieYear
                };    
            }
            
            foreach (var subtitle in subs)
            {
                result.AddSubtitleInfo(subtitle.SubTitleDownloadLink, subtitle.SubtitleFileName, GetCultureInfoFromLanguageId(subtitle.LanguageId));
            }
            return result;
        }

        private CultureInfo GetCultureInfoFromLanguageId(string languageId)
        {
            var ci = CultureInfo.GetCultures(CultureTypes.AllCultures)
                       .FirstOrDefault(x => x.ThreeLetterISOLanguageName == GetThreeLetterISOLanguageName(languageId));

            return ci;
        }

        private string GetLanguageCode(CultureInfo culture)
        {
            return culture.ThreeLetterISOLanguageName.ToLower() == "deu" ? "ger" : culture.ThreeLetterISOLanguageName;
        }

        private string GetThreeLetterISOLanguageName(string languageId)
        {
            return languageId == "ger" ? "deu" : languageId;
        }



        private string ExtractSeriesName(string fullname)
        {
            var series= fullname.Substring(from: "\"", until: "\"").Trim();
            return !string.IsNullOrWhiteSpace(series) ? series : fullname;
        }

        private string ExtractEpisodeName(string fullname)
        {
            var episode = fullname.Replace(ExtractSeriesName(fullname), string.Empty);
             episode = episode.Replace("\"", string.Empty).Trim();
            return !string.IsNullOrWhiteSpace(episode) ? episode : fullname;
        }
    }

    public static class StringExtensions
    {
        /// <summary>
        /// takes a substring between two anchor strings (or the end of the string if that anchor is null)
        /// </summary>
        /// <param name="this">a string</param>
        /// <param name="from">an optional string to search after</param>
        /// <param name="until">an optional string to search before</param>
        /// <param name="comparison">an optional comparison for the search</param>
        /// <returns>a substring based on the search</returns>
        public static string Substring(this string @this, string from = null, string until = null, StringComparison comparison = StringComparison.InvariantCulture)
        {
            var fromLength = (from ?? string.Empty).Length;
            var startIndex = !string.IsNullOrEmpty(from)
                ? @this.IndexOf(from, comparison) + fromLength
                : 0;

            if (startIndex < fromLength)
            {
                return null;
            }

            var endIndex = !string.IsNullOrEmpty(until)
            ? @this.IndexOf(until, startIndex + fromLength, comparison)
            : @this.Length;

            if (endIndex < 0)
            {
                return null;
            }

            var subString = @this.Substring(startIndex, endIndex - startIndex);
            return subString;
        }
    }
}
